#pragma once
#include "DXContext.h"
#include "ErrorCodes.h"
#include "NativePointer.h"
#include "enums.h"
#include "D3DBuffer.h"
#include "DataArray.h"
#include "VertexLayout.h"


namespace DXBase
{
	namespace D3D
	{
		ref class VertextLayout;

	    [Windows::Foundation::Metadata::WebHostHidden]
		public interface class IShape : IContextBound
		{
			uint32 GetIndexCount();
			uint32 GetVertexCount();
			void Validate(VertexLayout^ layout);
			property Format IndexFormat { Format get(); }
			property D3D::Topology Topology { D3D::Topology get(); }
			property Buffer^ IndicesBuffer { Buffer^ get(); }
			property Windows::Foundation::Collections::IVectorView<Buffer^>^ VerticesBuffer { Windows::Foundation::Collections::IVectorView<Buffer^>^ get(); }
			property Windows::Foundation::Collections::IVectorView<UINT>^ VerticesStride { Windows::Foundation::Collections::IVectorView<UINT>^ get(); }
		};

	    [Windows::Foundation::Metadata::WebHostHidden]
		public ref class Shape sealed : IShape
		{
		private:
			DataArray<MemoryBlock^>^ pVertices;
			DataArray<Buffer^>^ pBVertices;
			DataArray<UINT>^ pStrides;
			DataView<MemoryBlock^>^ pVVertices;
			DataView<Buffer^>^ pVBVertices;
			DataView<UINT>^ pVStrides;
			MemoryBlock^ pIndices;
			Buffer^ pBIndices;

		internal:
			virtual void ClearDXData() = IContextBound::ClearDXData 
			{
				for each (auto pB in pBVertices)
					pB->ClearDXData();
				pBIndices->ClearDXData();
			}
			virtual void LoadDXData() = IContextBound::LoadDXData 
			{
				for each (auto pB in pBVertices)
					pB->LoadDXData();
				pBIndices->LoadDXData();
			}
			virtual property DXContext^ Context
			{
				DXContext^ get() = IContextBound::Context::get { return pBIndices->Context; }
				void set(DXContext^ value) = IContextBound::Context::set
				{
					for each (auto pB in pBVertices)
						pB->Context = value;
					pBIndices->Context = value;
				}
			}

			virtual void Validate(VertexLayout^ layout) = IShape::Validate;
			virtual Format GetIndexFormat() = IShape::IndexFormat::get { return IndexFormat; };
			virtual D3D::Topology GetTopology() = IShape::Topology::get { return Topology; }

		public:
			Shape()
			{
				pVertices = ref new DataArray<MemoryBlock^>();
				pBVertices = ref new DataArray<Buffer^>();
				pStrides = ref new DataArray<UINT>();
				pVVertices = ref new DataView<MemoryBlock^>(pVertices);
				pVBVertices = ref new DataView<Buffer^>(pBVertices);
				pVStrides = ref new DataView<UINT>(pStrides);
				pIndices = ref new MemoryBlock();
				pBIndices = ref new Buffer();
				pBIndices->InitData = ref new SubresourceData(pIndices);
				pBIndices->BindFlags = BindFlag::IndexBuffer;
			}
			void AddVertexBuffer(UINT stride)
			{
				auto pV = ref new MemoryBlock();
				auto pBV = ref new Buffer();
				pBV->InitData = ref new SubresourceData(pV);
				pBV->BindFlags = BindFlag::VertexBuffer;
				pVertices->Append(pV);
				pBVertices->Append(pBV);
				pStrides->Append(stride);
			}
			void UpdateBuffers()
			{
				for each (auto pB in pBVertices)
					pB->UpdateBuffer();
				pBIndices->UpdateBuffer();
			}

			property Windows::Foundation::Collections::IVectorView<MemoryBlock^>^ Vertices { Windows::Foundation::Collections::IVectorView<MemoryBlock^>^ get() { return pVVertices; } }
			virtual property Windows::Foundation::Collections::IVectorView<Buffer^>^ VerticesBuffer { Windows::Foundation::Collections::IVectorView<Buffer^>^ get() { return pVBVertices; } }
			virtual property Windows::Foundation::Collections::IVectorView<UINT>^ VerticesStride { Windows::Foundation::Collections::IVectorView<UINT>^ get() { return pVStrides; } }
			property MemoryBlock^ Indices { MemoryBlock^ get() { return pIndices; } }
			virtual property Buffer^ IndicesBuffer { Buffer^ get() { return pBIndices; } }

			virtual uint32 GetIndexCount() { return pIndices->ByteSize / DXBase::GetSize(IndexFormat); }
			virtual uint32 GetVertexCount() { return (pVertices->Size > 0) ? pVertices->data[0]->ByteSize / pStrides->data[0] : 0; }

			property Format IndexFormat;
			property D3D::Topology Topology;
			property bool LeftHanded;
		};

	}
}
